package product

import (
	"context"
	"fmt"
	"strings"

	"mall/common/globalkey"
	"mall/common/jwt"
	"mall/common/utils/pointy"
	"mall/service/attachment/rpc/attachmentclient"
	"mall/service/backend/api/internal/svc"
	"mall/service/backend/api/internal/types"
	"mall/service/backend/common/enum/errorcode"
	"mall/service/backend/common/errorx"
	"mall/service/product/rpc/productclient"

	// "github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type CreateProductLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewCreateProductLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateProductLogic {
	return &CreateProductLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *CreateProductLogic) CreateProduct(req *types.CreateProductReq) (resp *types.BaseMsgResp, err error) {
	// logrus.Info(fmt.Sprintf("CreateProductReq: %+v", req))

	if req.Title == nil || len(strings.TrimSpace(*req.Title)) == 0 {
		return nil, errorx.NewCodeError(errorcode.InvalidArgument,
			l.svcCtx.Trans.Trans(l.ctx, "product.titleRequired"))
	}

	if req.ProductCode == nil || len(strings.TrimSpace(*req.ProductCode)) == 0 {
		return nil, errorx.NewCodeError(errorcode.InvalidArgument,
			l.svcCtx.Trans.Trans(l.ctx, "product.codeRequired"))
	}

	var content *string
	var contentFiltered *string
	if req.Content != nil && len(strings.TrimSpace(*req.Content)) > 0 {
		parts := strings.Split(strings.TrimSpace(*req.Content), globalkey.EditorSplitSymbol)
		if len(parts) > 0 {
			content = pointy.GetPointer(parts[0])
		}
		if len(parts) > 1 {
			contentFiltered = pointy.GetPointer(parts[1])
		}
	}

	var tracing *string
	var tracingFiltered *string
	if req.Tracing != nil && len(strings.TrimSpace(*req.Tracing)) > 0 {
		parts := strings.Split(strings.TrimSpace(*req.Tracing), globalkey.EditorSplitSymbol)
		if len(parts) > 0 {
			tracing = pointy.GetPointer(parts[0])
		}
		if len(parts) > 1 {
			tracingFiltered = pointy.GetPointer(parts[1])
		}
	}

	var meta []*productclient.MetaInfo
	if len(req.Meta) > 0 {
		for _, v := range req.Meta {
			meta = append(meta, &productclient.MetaInfo{
				Key:   v.Key,
				Value: v.Value,
			})
		}
	}
	if req.Abbr != nil && len(strings.TrimSpace(*req.Abbr)) > 0 {
		meta = append(meta, &productclient.MetaInfo{
			Key:   pointy.GetPointer("abbr"),
			Value: pointy.GetPointer(strings.TrimSpace(*req.Abbr)),
		})
	}

	var attrs []*productclient.ProductAttrInfo
	if len(req.Attrs) > 0 {
		for _, attr := range req.Attrs {
			var opts []*productclient.ProductAttrOptInfo
			if len(attr.Options) > 0 {
				for _, opt := range attr.Options {
					opts = append(opts, &productclient.ProductAttrOptInfo{
						Id:       opt.Id,
						Label:    opt.Label,
						Slug:     opt.Slug,
						MediaId:  opt.ImgId,
						MediaUrl: opt.ImgUrl,
					})
				}

				attrs = append(attrs, &productclient.ProductAttrInfo{
					Id:       attr.Id,
					Label:    attr.Label,
					Slug:     attr.Slug,
					HasMedia: attr.HasImage,
					Options:  opts,
				})
			}
		}
	}

	var specs []*productclient.ProductAttrInfo
	if len(req.Specs) > 0 {
		for _, spec := range req.Specs {
			var opts []*productclient.ProductAttrOptInfo
			if len(spec.Options) > 0 {
				for _, opt := range spec.Options {
					opts = append(opts, &productclient.ProductAttrOptInfo{
						Id:       opt.Id,
						Key:      opt.Key,
						Label:    opt.Label,
						Slug:     opt.Slug,
						MediaId:  opt.ImgId,
						MediaUrl: opt.ImgUrl,
					})
				}
				specs = append(specs, &productclient.ProductAttrInfo{
					Id:       spec.Id,
					Label:    spec.Label,
					Slug:     spec.Slug,
					HasMedia: spec.HasImage,
					Options:  opts,
				})
			}
		}
	}

	var skus []*productclient.ProductVariationInfo
	if len(req.Skus) > 0 {
		for _, sku := range req.Skus {
			if len(sku.Specs) > 0 {
				var skuSpecs []*productclient.ProductAttrInfo
				for _, spec := range sku.Specs {
					var opts []*productclient.ProductAttrOptInfo
					if len(spec.Options) > 0 {
						for _, opt := range spec.Options {
							opts = append(opts, &productclient.ProductAttrOptInfo{
								Id:       opt.Id,
								Key:      opt.Key,
								Label:    opt.Label,
								Slug:     opt.Slug,
								MediaId:  opt.ImgId,
								MediaUrl: opt.ImgUrl,
							})
						}
						skuSpecs = append(skuSpecs, &productclient.ProductAttrInfo{
							Id:      spec.Id,
							Label:   spec.Label,
							Slug:    spec.Slug,
							Options: opts,
						})
					}
				}
				skus = append(skus, &productclient.ProductVariationInfo{
					Id:           sku.Id,
					Key:          sku.Key,
					RetailPrice:  sku.RetailPrice,
					CounterPrice: sku.CounterPrice,
					GemPrice:     sku.GemPrice,
					SkuCode:      sku.SkuCode,
					Status:       sku.Status,
					Weight:       sku.Weight,
					SaleCount:    sku.SaleCount,
					MediaId:      sku.ImgId,
					MediaUrl:     sku.ImgUrl,
					Specs:        skuSpecs,
				})
			}
		}
	}

	var allMedia []*productclient.MediaInfo
	newThumbMap := make(map[string]*types.MediaInfo)
	newMediaMap := make(map[string]*types.MediaInfo)
	var newMediaIds []string // 用于查询 attachmentRpc
	thumbnail := pointy.GetPointer(uint32(1))
	var newMedia []*productclient.MediaInfo
	var newAttachmentIds []string // 用于主动通知 attachmentRpc 附件已使用
	if len(req.AllMedia) > 0 {    // 富文本所有图片
		for _, v := range req.AllMedia {
			allMedia = append(allMedia, &productclient.MediaInfo{
				Id:  v.Id,
				Url: v.Url,
			})
		}
	}

	if len(req.NewThumb) > 0 { // 封面图
		for _, v := range req.NewThumb {
			if v.Id != nil && len(*v.Id) > 0 {
				if _, ok := newThumbMap[*v.Id]; !ok { // 忽略重复id
					newThumbMap[*v.Id] = v
					newMediaIds = append(newMediaIds, *v.Id)
				}
			} else {
				newMedia = append(newMedia, &productclient.MediaInfo{
					Thumbnail: thumbnail,
					Order:     v.Order,
					Url:       v.Url,
					Name:      v.Name,
					MimeType:  v.MimeType,
					AltText:   v.AltText,
					MetaData:  v.MetaData,
				})
			}
		}
	}

	if len(req.NewMedia) > 0 { // 富文本新图片
		for _, v := range req.NewMedia {
			if v.Id != nil && len(*v.Id) > 0 {
				if _, ok := newMediaMap[*v.Id]; !ok { // 忽略重复id
					newMediaMap[*v.Id] = v
					newMediaIds = append(newMediaIds, *v.Id)
				}
			} else {
				newMedia = append(newMedia, &productclient.MediaInfo{
					Order:    v.Order,
					Url:      v.Url,
					Name:     v.Name,
					MimeType: v.MimeType,
					AltText:  v.AltText,
					MetaData: v.MetaData,
				})
			}
		}
	}

	if len(newMediaIds) > 0 {
		res, err := l.svcCtx.AttachmentRpc.BackendGetFileList(l.ctx, &attachmentclient.FileListReq{
			Ids: pointy.GetPointer(strings.Join(newMediaIds, ",")),
		})
		if err != nil {
			return nil, err
		}

		if len(res.List) > 0 {
			for _, v := range res.List {
				if v.Id != nil && len(*v.Id) > 0 {
					mediaId := *v.Id
					var url string
					if v.Url != nil && len(*v.Url) > 0 {
						url = fmt.Sprintf("%s%s", l.svcCtx.Config.NfsConf.StaticUrl, *v.Url)
					}
					if len(url) == 0 && v.Path != nil && len(*v.Path) > 0 {
						url = fmt.Sprintf("%s%s", l.svcCtx.Config.NfsConf.ProxyUrl, *v.Path)
					}

					if media, ok := newThumbMap[mediaId]; ok {
						newMedia = append(newMedia, &productclient.MediaInfo{
							Id:        v.Id,
							Thumbnail: thumbnail,
							Order:     media.Order,
							Uri:       media.Url,
							Url:       pointy.GetPointer(url),
							Name:      media.Name,
							MimeType:  media.MimeType,
							AltText:   media.AltText,
							MetaData:  media.MetaData,
						})
						newAttachmentIds = append(newAttachmentIds, mediaId)
						continue
					}

					if media, ok := newMediaMap[mediaId]; ok {
						newMedia = append(newMedia, &productclient.MediaInfo{
							Id:       v.Id,
							Order:    media.Order,
							Uri:      media.Url,
							Url:      pointy.GetPointer(url),
							Name:     media.Name,
							MimeType: media.MimeType,
							AltText:  media.AltText,
							MetaData: media.MetaData,
						})
						newAttachmentIds = append(newAttachmentIds, mediaId)
					}
				}
			}
		}
	}

	var publicDate *string
	var visibility *uint32
	if req.PublicTime != nil {
		if *req.PublicTime == 2 { // 定时发布
			publicDate = req.PublicDate
		} else if *req.PublicTime == 3 { // 仓库中
			visibility = pointy.GetPointer(globalkey.PostVisibilityPrivate)
		}
	}
	createdBy := pointy.GetPointer(jwt.GetBackendUserId(l.ctx))

	res, err := l.svcCtx.ProductRpc.CreateProduct(l.ctx, &productclient.ProductInfo{
		Title:           req.Title,       //
		Slug:            req.Slug,        //
		ProductCode:     req.ProductCode, //
		CategoryId:      req.CategoryId,  //
		Content:         content,         //
		ContentFiltered: contentFiltered, //
		Excerpt:         req.Excerpt,     //
		Status:          req.Status,      //
		Tracing:         tracing,         //
		TracingFiltered: tracingFiltered, //
		Sort:            req.Sort,
		PublicDate:      publicDate,
		Visibility:      visibility,
		SellPoint:       req.SellPoint,   //
		StockUnit:       req.StockUnit,   //
		ShowStock:       req.ShowStock,   //
		CategoryIds:     req.CategoryIds, //
		TagIds:          req.TagIds,      //
		CreatedBy:       createdBy,       //
		Meta:            meta,            //
		AllMedia:        allMedia,        //
		NewMedia:        newMedia,        //
		RelationIds:     req.RelationIds,
		Attrs:           attrs,
		Specs:           specs,
		Skus:            skus,
	})
	if err != nil {
		return nil, err
	}

	if len(newAttachmentIds) > 0 {
		_, err = l.svcCtx.AttachmentRpc.CreateFileLog(l.ctx, &attachmentclient.CreateFileLogReq{
			FileIds:   newAttachmentIds,
			Put:       pointy.GetPointer(uint32(1)),
			Thumbnail: pointy.GetPointer(uint32(1)),
			// Watermark:  pointy.GetPointer(uint32(1)),
			ObjectId:   pointy.GetPointer(res.Id),
			ObjectType: pointy.GetPointer(uint32(globalkey.AttachmentLogTypeProduct)),
		})
		if err != nil {
			logx.Errorw("CreateProduct AttachmentRpc.CreateFileLog err", logx.Field("detail", err.Error()))
		}
	}

	return &types.BaseMsgResp{
		Success: true,
		Msg:     l.svcCtx.Trans.Trans(l.ctx, res.Msg),
	}, nil
}
